/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.games.epkb.controller;

import it.polimi.games.epkb.controller.exceptions.IllegalOrphanException;
import it.polimi.games.epkb.controller.exceptions.NonexistentEntityException;
import it.polimi.games.epkb.controller.exceptions.PreexistingEntityException;
import it.polimi.games.epkb.entityClasses.DataFile;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import it.polimi.games.epkb.entityClasses.Component;
import java.util.ArrayList;
import java.util.Collection;
import it.polimi.games.epkb.entityClasses.Annotation;
import it.polimi.games.epkb.entityClasses.ActivityData;
import javax.transaction.UserTransaction;

/**
 *
 * @author plebani
 */
public class DataFileJpaController implements Serializable {

    public DataFileJpaController(EntityManagerFactory emf) {
        this.utx = null;
        this.emf = emf;
    }

    public DataFileJpaController(UserTransaction utx, EntityManagerFactory emf) {
        this.utx = utx;
        this.emf = emf;
    }
    private UserTransaction utx = null;
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(DataFile dataFile) throws PreexistingEntityException, Exception {
        if (dataFile.getComponentCollection() == null) {
            dataFile.setComponentCollection(new ArrayList<Component>());
        }
        if (dataFile.getAnnotationCollection() == null) {
            dataFile.setAnnotationCollection(new ArrayList<Annotation>());
        }
        if (dataFile.getActivityDataCollection() == null) {
            dataFile.setActivityDataCollection(new ArrayList<ActivityData>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Collection<Component> attachedComponentCollection = new ArrayList<Component>();
            for (Component componentCollectionComponentToAttach : dataFile.getComponentCollection()) {
                componentCollectionComponentToAttach = em.getReference(componentCollectionComponentToAttach.getClass(), componentCollectionComponentToAttach.getId());
                attachedComponentCollection.add(componentCollectionComponentToAttach);
            }
            dataFile.setComponentCollection(attachedComponentCollection);
            Collection<Annotation> attachedAnnotationCollection = new ArrayList<Annotation>();
            for (Annotation annotationCollectionAnnotationToAttach : dataFile.getAnnotationCollection()) {
                annotationCollectionAnnotationToAttach = em.getReference(annotationCollectionAnnotationToAttach.getClass(), annotationCollectionAnnotationToAttach.getId());
                attachedAnnotationCollection.add(annotationCollectionAnnotationToAttach);
            }
            dataFile.setAnnotationCollection(attachedAnnotationCollection);
            Collection<ActivityData> attachedActivityDataCollection = new ArrayList<ActivityData>();
            for (ActivityData activityDataCollectionActivityDataToAttach : dataFile.getActivityDataCollection()) {
                activityDataCollectionActivityDataToAttach = em.getReference(activityDataCollectionActivityDataToAttach.getClass(), activityDataCollectionActivityDataToAttach.getActivityDataPK());
                attachedActivityDataCollection.add(activityDataCollectionActivityDataToAttach);
            }
            dataFile.setActivityDataCollection(attachedActivityDataCollection);
            em.persist(dataFile);
            for (Component componentCollectionComponent : dataFile.getComponentCollection()) {
                componentCollectionComponent.getDataFileCollection().add(dataFile);
                componentCollectionComponent = em.merge(componentCollectionComponent);
            }
            for (Annotation annotationCollectionAnnotation : dataFile.getAnnotationCollection()) {
                DataFile oldIdDataFileOfAnnotationCollectionAnnotation = annotationCollectionAnnotation.getIdDataFile();
                annotationCollectionAnnotation.setIdDataFile(dataFile);
                annotationCollectionAnnotation = em.merge(annotationCollectionAnnotation);
                if (oldIdDataFileOfAnnotationCollectionAnnotation != null) {
                    oldIdDataFileOfAnnotationCollectionAnnotation.getAnnotationCollection().remove(annotationCollectionAnnotation);
                    oldIdDataFileOfAnnotationCollectionAnnotation = em.merge(oldIdDataFileOfAnnotationCollectionAnnotation);
                }
            }
            for (ActivityData activityDataCollectionActivityData : dataFile.getActivityDataCollection()) {
                DataFile oldDataFileOfActivityDataCollectionActivityData = activityDataCollectionActivityData.getDataFile();
                activityDataCollectionActivityData.setDataFile(dataFile);
                activityDataCollectionActivityData = em.merge(activityDataCollectionActivityData);
                if (oldDataFileOfActivityDataCollectionActivityData != null) {
                    oldDataFileOfActivityDataCollectionActivityData.getActivityDataCollection().remove(activityDataCollectionActivityData);
                    oldDataFileOfActivityDataCollectionActivityData = em.merge(oldDataFileOfActivityDataCollectionActivityData);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findDataFile(dataFile.getId()) != null) {
                throw new PreexistingEntityException("DataFile " + dataFile + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(DataFile dataFile) throws IllegalOrphanException, NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            DataFile persistentDataFile = em.find(DataFile.class, dataFile.getId());
            Collection<Component> componentCollectionOld = persistentDataFile.getComponentCollection();
            Collection<Component> componentCollectionNew = dataFile.getComponentCollection();
            Collection<Annotation> annotationCollectionOld = persistentDataFile.getAnnotationCollection();
            Collection<Annotation> annotationCollectionNew = dataFile.getAnnotationCollection();
            Collection<ActivityData> activityDataCollectionOld = persistentDataFile.getActivityDataCollection();
            Collection<ActivityData> activityDataCollectionNew = dataFile.getActivityDataCollection();
            List<String> illegalOrphanMessages = null;
            for (ActivityData activityDataCollectionOldActivityData : activityDataCollectionOld) {
                if (!activityDataCollectionNew.contains(activityDataCollectionOldActivityData)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain ActivityData " + activityDataCollectionOldActivityData + " since its dataFile field is not nullable.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Collection<Component> attachedComponentCollectionNew = new ArrayList<Component>();
            for (Component componentCollectionNewComponentToAttach : componentCollectionNew) {
                componentCollectionNewComponentToAttach = em.getReference(componentCollectionNewComponentToAttach.getClass(), componentCollectionNewComponentToAttach.getId());
                attachedComponentCollectionNew.add(componentCollectionNewComponentToAttach);
            }
            componentCollectionNew = attachedComponentCollectionNew;
            dataFile.setComponentCollection(componentCollectionNew);
            Collection<Annotation> attachedAnnotationCollectionNew = new ArrayList<Annotation>();
            for (Annotation annotationCollectionNewAnnotationToAttach : annotationCollectionNew) {
                annotationCollectionNewAnnotationToAttach = em.getReference(annotationCollectionNewAnnotationToAttach.getClass(), annotationCollectionNewAnnotationToAttach.getId());
                attachedAnnotationCollectionNew.add(annotationCollectionNewAnnotationToAttach);
            }
            annotationCollectionNew = attachedAnnotationCollectionNew;
            dataFile.setAnnotationCollection(annotationCollectionNew);
            Collection<ActivityData> attachedActivityDataCollectionNew = new ArrayList<ActivityData>();
            for (ActivityData activityDataCollectionNewActivityDataToAttach : activityDataCollectionNew) {
                activityDataCollectionNewActivityDataToAttach = em.getReference(activityDataCollectionNewActivityDataToAttach.getClass(), activityDataCollectionNewActivityDataToAttach.getActivityDataPK());
                attachedActivityDataCollectionNew.add(activityDataCollectionNewActivityDataToAttach);
            }
            activityDataCollectionNew = attachedActivityDataCollectionNew;
            dataFile.setActivityDataCollection(activityDataCollectionNew);
            dataFile = em.merge(dataFile);
            for (Component componentCollectionOldComponent : componentCollectionOld) {
                if (!componentCollectionNew.contains(componentCollectionOldComponent)) {
                    componentCollectionOldComponent.getDataFileCollection().remove(dataFile);
                    componentCollectionOldComponent = em.merge(componentCollectionOldComponent);
                }
            }
            for (Component componentCollectionNewComponent : componentCollectionNew) {
                if (!componentCollectionOld.contains(componentCollectionNewComponent)) {
                    componentCollectionNewComponent.getDataFileCollection().add(dataFile);
                    componentCollectionNewComponent = em.merge(componentCollectionNewComponent);
                }
            }
            for (Annotation annotationCollectionOldAnnotation : annotationCollectionOld) {
                if (!annotationCollectionNew.contains(annotationCollectionOldAnnotation)) {
                    annotationCollectionOldAnnotation.setIdDataFile(null);
                    annotationCollectionOldAnnotation = em.merge(annotationCollectionOldAnnotation);
                }
            }
            for (Annotation annotationCollectionNewAnnotation : annotationCollectionNew) {
                if (!annotationCollectionOld.contains(annotationCollectionNewAnnotation)) {
                    DataFile oldIdDataFileOfAnnotationCollectionNewAnnotation = annotationCollectionNewAnnotation.getIdDataFile();
                    annotationCollectionNewAnnotation.setIdDataFile(dataFile);
                    annotationCollectionNewAnnotation = em.merge(annotationCollectionNewAnnotation);
                    if (oldIdDataFileOfAnnotationCollectionNewAnnotation != null && !oldIdDataFileOfAnnotationCollectionNewAnnotation.equals(dataFile)) {
                        oldIdDataFileOfAnnotationCollectionNewAnnotation.getAnnotationCollection().remove(annotationCollectionNewAnnotation);
                        oldIdDataFileOfAnnotationCollectionNewAnnotation = em.merge(oldIdDataFileOfAnnotationCollectionNewAnnotation);
                    }
                }
            }
            for (ActivityData activityDataCollectionNewActivityData : activityDataCollectionNew) {
                if (!activityDataCollectionOld.contains(activityDataCollectionNewActivityData)) {
                    DataFile oldDataFileOfActivityDataCollectionNewActivityData = activityDataCollectionNewActivityData.getDataFile();
                    activityDataCollectionNewActivityData.setDataFile(dataFile);
                    activityDataCollectionNewActivityData = em.merge(activityDataCollectionNewActivityData);
                    if (oldDataFileOfActivityDataCollectionNewActivityData != null && !oldDataFileOfActivityDataCollectionNewActivityData.equals(dataFile)) {
                        oldDataFileOfActivityDataCollectionNewActivityData.getActivityDataCollection().remove(activityDataCollectionNewActivityData);
                        oldDataFileOfActivityDataCollectionNewActivityData = em.merge(oldDataFileOfActivityDataCollectionNewActivityData);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                String id = dataFile.getId();
                if (findDataFile(id) == null) {
                    throw new NonexistentEntityException("The dataFile with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(String id) throws IllegalOrphanException, NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            DataFile dataFile;
            try {
                dataFile = em.getReference(DataFile.class, id);
                dataFile.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The dataFile with id " + id + " no longer exists.", enfe);
            }
            List<String> illegalOrphanMessages = null;
            Collection<ActivityData> activityDataCollectionOrphanCheck = dataFile.getActivityDataCollection();
            for (ActivityData activityDataCollectionOrphanCheckActivityData : activityDataCollectionOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This DataFile (" + dataFile + ") cannot be destroyed since the ActivityData " + activityDataCollectionOrphanCheckActivityData + " in its activityDataCollection field has a non-nullable dataFile field.");
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Collection<Component> componentCollection = dataFile.getComponentCollection();
            for (Component componentCollectionComponent : componentCollection) {
                componentCollectionComponent.getDataFileCollection().remove(dataFile);
                componentCollectionComponent = em.merge(componentCollectionComponent);
            }
            Collection<Annotation> annotationCollection = dataFile.getAnnotationCollection();
            for (Annotation annotationCollectionAnnotation : annotationCollection) {
                annotationCollectionAnnotation.setIdDataFile(null);
                annotationCollectionAnnotation = em.merge(annotationCollectionAnnotation);
            }
            em.remove(dataFile);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<DataFile> findDataFileEntities() {
        return findDataFileEntities(true, -1, -1);
    }

    public List<DataFile> findDataFileEntities(int maxResults, int firstResult) {
        return findDataFileEntities(false, maxResults, firstResult);
    }

    private List<DataFile> findDataFileEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(DataFile.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public DataFile findDataFile(String id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(DataFile.class, id);
        } finally {
            em.close();
        }
    }

    public int getDataFileCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<DataFile> rt = cq.from(DataFile.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }
    
}
